home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / IPROUTE.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  15KB  |  597 lines

  1. /* Lower half of IP, consisting of gateway routines
  2.  * Includes routing and options processing code
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "internet.h"
  7. #include "timer.h"
  8. #include "netuser.h"
  9. #include "ip.h"
  10. #include "icmp.h"
  11. #include "iface.h"
  12. #include "trace.h"
  13.  
  14. struct route *routes[32][NROUTE];    /* Routing table */
  15. struct route r_default;            /* Default route entry */
  16.  
  17. int32 ip_addr;
  18. struct ip_stats ip_stats;
  19.  
  20. #ifndef    GWONLY
  21. struct mbuf *loopq;    /* Queue for loopback packets */
  22. #endif
  23.  
  24. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  25.  * coming or going, must pass.
  26.  *
  27.  * This router is a temporary hack, since it only does host-specific or
  28.  * default routing (no hierarchical routing yet).
  29.  *
  30.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  31.  * broadcast. The router will kick the packet upstairs regardless of the
  32.  * IP destination address.
  33.  */
  34. void
  35. ip_route(bp,rxbroadcast)
  36. struct mbuf *bp;
  37. char rxbroadcast;    /* True if packet had link broadcast address */
  38. {
  39.     struct mbuf *htonip();
  40.     struct ip ip;            /* IP header being processed */
  41.     int16 ip_len;            /* IP header length */
  42.     int16 length;            /* Length of data portion */
  43.     int32 gateway;            /* Gateway IP address */
  44.     register struct route *rp;    /* Route table entry */
  45.     struct route *rt_lookup();
  46.     int16 offset;            /* Offset into current fragment */
  47.     int strict = 0;            /* Strict source routing flag */
  48.     char precedence;        /* Extracted from tos field */
  49.     char delay;
  50.     char throughput;
  51.     char reliability;
  52.     int16 opt_len;    /* Length of current option */
  53.     char *opt;    /* -> beginning of current option */
  54.     char *ptr;    /* -> pointer field in source route fields */
  55.     struct mbuf *tbp;
  56.  
  57.     ip_stats.total++;
  58.     if(len_mbuf(bp) < IPLEN){
  59.         /* The packet is shorter than a legal IP header */
  60.         ip_stats.runt++;
  61.         free_p(bp);
  62.         return;
  63.     }
  64.     /* Sneak a peek at the IP header's IHL field to find its length */
  65.     ip_len = (bp->data[0] & 0xf) << 2;
  66.     if(ip_len < IPLEN){
  67.         /* The IP header length field is too small */
  68.         ip_stats.length++;
  69.         free_p(bp);
  70.         return;
  71.     }
  72.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  73.         /* Bad IP header checksum; discard */
  74.         ip_stats.checksum++;
  75.         free_p(bp);
  76.         return;
  77.     }
  78.     /* Extract IP header */
  79.     ntohip(&ip,&bp);
  80.  
  81.     if(ip.version != IPVERSION){
  82.         /* We can't handle this version of IP */
  83.         ip_stats.version++;
  84.         free_p(bp);
  85.         return;
  86.     }
  87.     /* Trim data segment if necessary. */
  88.     length = ip.length - ip_len;    /* Length of data portion */
  89.     trim_mbuf(&bp,length);    
  90.                 
  91.     /* Process options, if any. Also compute length of secondary IP
  92.      * header in case fragmentation is needed later
  93.      */
  94.     strict = 0;
  95.     for(opt = ip.options; opt < &ip.options[ip.optlen];opt += opt_len){
  96.         int32 get32();
  97.  
  98.         /* Most options have a length field. If this is a EOL or NOOP,
  99.          * this (garbage) value won't be used
  100.          */
  101.         opt_len = opt[1] & 0xff;
  102.  
  103.         switch(opt[0] & OPT_NUMBER){
  104.         case IP_EOL:
  105.             goto no_opt;    /* End of options list, we're done */
  106.         case IP_NOOP:
  107.             opt_len = 1;
  108.             break;        /* No operation, skip to next option */
  109.         case IP_SSROUTE:    /* Strict source route & record route */
  110.             strict = 1;    /* note fall-thru */
  111.         case IP_LSROUTE:    /* Loose source route & record route */
  112.             /* Source routes are ignored unless we're in the
  113.              * destination field
  114.              */
  115.             if(ip.dest != ip_addr)
  116.                 break;    /* Skip to next option */
  117.             if((opt[2] & 0xff) >= opt_len){
  118.                 break;    /* Route exhausted; it's for us */
  119.             }
  120.             /* Put address for next hop into destination field,
  121.              * put our address into the route field, and bump
  122.              * the pointer
  123.              */
  124.             ptr = opt + (opt[2] & 0xff) - 1;
  125.             ip.dest = get32(ptr);
  126.             put32(ptr,ip_addr);
  127.             opt[2] += 4;
  128.             break;
  129.         case IP_RROUTE:    /* Record route */
  130.             if((opt[2] & 0xff) >= opt_len){
  131.                 /* Route area exhausted; kick back an error */
  132.                 union icmp_args icmp_args;
  133.  
  134.                 icmp_args.pointer = IPLEN + opt - ip.options;
  135.                 icmp_output(&ip,bp,PARAM_PROB,0,&icmp_args);
  136.                 free_p(bp);
  137.                 return;
  138.             }
  139.             /* Add our address to the route */
  140.             ptr = opt + (opt[2] & 0xff) - 1;
  141.             ptr = put32(ptr,ip_addr);
  142.             opt[2] += 4;
  143.             break;
  144.         }
  145.     }
  146. no_opt:
  147.  
  148.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  149.     if(ip.dest == ip_addr || rxbroadcast){
  150. #ifdef    GWONLY
  151.     /* We're only a gateway, we have no host level protocols */
  152.         if(!rxbroadcast)
  153.             icmp_output(&ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  154.         free_p(bp);
  155. #else
  156.         /* Put IP header back on */
  157.         if((bp = htonip(&ip,bp)) == NULLBUF)
  158.             return;
  159.  
  160.         /* If this is a local loopback packet, place on the loopback
  161.          * queue for processing in the main loop. This prevents the
  162.          * infinite stack recursion and other problems that would
  163.          * otherwise occur when we talk to ourselves, e.g., with ftp
  164.          */
  165.         if(ip.source == ip_addr){
  166.             /* LOOPBACK TRACING GOES HERE */
  167.             /* Copy loopback packet into new buffer.
  168.              * This avoids an obscure problem with TCP which
  169.              * dups its outgoing data before transmission and
  170.              * then frees it when an ack comes, even though the
  171.              * receiver might not have actually read it yet
  172.              */
  173.             tbp = copy_p(bp,len_mbuf(bp));
  174.             free_p(bp);
  175.             if(tbp != NULLBUF)
  176.                 enqueue(&loopq,tbp);
  177.         } else {
  178.             ip_recv(bp,rxbroadcast);
  179.         }
  180. #endif
  181.         return;
  182.     }
  183.  
  184.     /* Decrement TTL and discard if zero */
  185.     if(--ip.ttl == 0){
  186.         /* Send ICMP "Time Exceeded" message */
  187.         icmp_output(&ip,bp,TIME_EXCEED,0,NULLICMP);
  188.         free_p(bp);
  189.         return;
  190.     }
  191.     /* Look up target address in routing table */
  192.     if((rp = rt_lookup(ip.dest)) == NULLROUTE){
  193.         /* No route exists, return unreachable message */
  194.         icmp_output(&ip,bp,DEST_UNREACH,HOST_UNREACH,NULLICMP);
  195.         free_p(bp);
  196.         return;
  197.     }
  198.     /* Find gateway; zero gateway in routing table means "send direct" */
  199.     if(rp->gateway == (int32)0)
  200.         gateway = ip.dest;
  201.     else
  202.         gateway = rp->gateway;
  203.  
  204.     if(strict && gateway != ip.dest){
  205.         /* Strict source routing requires a direct entry */
  206.         icmp_output(&ip,bp,DEST_UNREACH,ROUTE_FAIL,NULLICMP);
  207.         free_p(bp);
  208.         return;
  209.     }
  210.     precedence = PREC(ip.tos);
  211.     delay = ip.tos & DELAY;
  212.     throughput = ip.tos & THRUPUT;
  213.     reliability = ip.tos & RELIABILITY;
  214.  
  215.     if(ip.length <= rp->interface->mtu){
  216.         /* Datagram smaller than interface MTU; put header
  217.          * back on and send normally
  218.          */
  219.         bp = htonip(&ip,bp);
  220.         (*rp->interface->send)(bp,rp->interface,gateway,
  221.             precedence,delay,throughput,reliability);
  222.         return;
  223.     }
  224.     /* Fragmentation needed */
  225.     if(ip.fl_offs & DF){
  226.         /* Don't Fragment set; return ICMP message and drop */
  227.         icmp_output(&ip,bp,DEST_UNREACH,FRAG_NEEDED,NULLICMP);
  228.         free_p(bp);
  229.         return;
  230.     }
  231.     /* Create fragments */
  232.     offset = (ip.fl_offs & F_OFFSET) << 3;
  233.     while(length != 0){        /* As long as there's data left */
  234.         int16 fragsize;        /* Size of this fragment's data */
  235.         struct mbuf *f_data;    /* Data portion of fragment */
  236.  
  237.         /* After the first fragment, should remove those
  238.          * options that aren't supposed to be copied on fragmentation
  239.          */
  240.         ip.fl_offs = offset >> 3;
  241.         if(length + ip_len <= rp->interface->mtu){
  242.             /* Last fragment; send all that remains */
  243.             fragsize = length;
  244.         } else {
  245.             /* More to come, so send multiple of 8 bytes */
  246.             fragsize = (rp->interface->mtu - ip_len) & 0xfff8;
  247.             ip.fl_offs |= MF;
  248.         }
  249.         ip.length = fragsize + ip_len;
  250.  
  251.         /* Move the data fragment into a new, separate mbuf */
  252.         if((f_data = alloc_mbuf(fragsize)) == NULLBUF){
  253.             free_p(bp);
  254.             break;
  255.         }
  256.         f_data->cnt = pullup(&bp,f_data->data,fragsize);
  257.  
  258.         /* Put IP header back on */
  259.         if((f_data = htonip(&ip,f_data)) == NULLBUF){
  260.             free_p(bp);
  261.             break;
  262.         }
  263.         /* and ship it out */
  264.         (*rp->interface->send)(f_data,rp->interface,gateway,
  265.             precedence,delay,throughput,reliability);
  266.  
  267.         offset += fragsize;
  268.         length -= fragsize;
  269.     }
  270. }
  271.  
  272. /* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
  273. int
  274. rt_add(target,bits,gateway,metric,interface)
  275. int32 target;    /* Target IP address prefix */
  276. unsigned bits;    /* Size of target address prefix in bits (0-32) */
  277. int32 gateway;
  278. int metric;
  279. struct interface *interface;
  280. {
  281.     struct route *rp,**hp,*rt_lookup();
  282.     int16 hash_ip(),i;
  283.  
  284.     if(interface == NULLIF)
  285.         return -1;
  286.  
  287.     /* Zero bits refers to the default route */
  288.     if(bits == 0){
  289.         rp = &r_default;
  290.     } else {
  291.         if(bits > 32)
  292.             bits = 32;
  293.  
  294.         /* Mask off don't-care bits */